package com.sarc.games;

import java.util.concurrent.locks.ReentrantLock;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import org.opencv.calib3d.Calib3d;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

public class TouchBalls /*extends Thread*/ implements Renderer {
	private static final String TAG = "SARC.TOUCHBALLS";
	SensorMathematics sensor;
	//Ball[][] balls = new Ball[4][4];
	ReentrantLock camPosLock, camImageLock;
	
	boolean shouldDrawScene = false;
	
	Mat rv=null, 
		tv=null, 
		image = null;
	
	static Mat trianglePointRv;
	
	static Mat trianglePoint1Tv;
	static Mat trianglePoint2Tv;
	static Mat trianglePoint3Tv;
	
	public TouchBalls(SensorMathematics sensor)
	{
		this.sensor = sensor;
		/*
        for (int i = 0; i < 4; i++)
        {
        	for (int j = 0; j < 4; j++){
        		float[] newPt = new float[]{-3 + 2*i, -3 + 2*j, -8};
        		balls[i][j] = new Ball(newPt);
        	}
        }
        */
        camPosLock = new ReentrantLock();
        camImageLock = new ReentrantLock();
		trianglePoint1Tv = Mat.zeros(3, 1, CvType.CV_64FC1);
		trianglePoint2Tv = Mat.zeros(3, 1, CvType.CV_64FC1);
		trianglePoint2Tv.put(0, 0, new double[]{1});
		trianglePoint3Tv = Mat.zeros(3, 1, CvType.CV_64FC1);
		trianglePoint3Tv.put(1, 0, new double[]{1});
		
		trianglePointRv = Mat.eye(3, 3, CvType.CV_64FC1);
 		NativeInit();
	}
	
	public void setNewCameraPosition(Mat rv, Mat tv)
	{
		camPosLock.lock();
		try
		{
			if (this.rv == null)
			{
				this.rv = new Mat(rv.size(), rv.type());
			}
			if (this.tv == null)
			{
				this.tv = new Mat(tv.size(), tv.type());
			}
			rv.copyTo(this.rv);
			tv.copyTo(this.tv);
			
			NativeUpdateCameraPosition(this.rv.nativeObj, this.tv.nativeObj);
			Log.d(TAG, "Camera position updated" + tv.dump() + rv.dump());
		}
		finally
		{
			camPosLock.unlock();
		}
	}
	
	public void setShouldDrawScene(boolean shouldDrawScene)
	{
		this.shouldDrawScene = shouldDrawScene;
	}
	
	public void setNewImageBuffer(Mat img)
	{
		camImageLock.lock();
		try
		{
			if (this.image == null)
			{
				this.image = new Mat(img.size(), img.type());
				Log.d(TAG, "created new image");
			}
			img.copyTo(image);
		}
		finally
		{
			camImageLock.unlock();
		}
		//this.image = img;
	}
	
	public void setReferencePoint(Mat refPt)
	{
		float[] data = new float[1];
		
		refPt.get(0, 0, data);
		float refX = data[0];
		
		refPt.get(0, 1, data);
		float refY = data[0];
		
		refPt.get(0, 2, data);
		float refZ = data[0];

		NativeUpdateReferencePoint(refX, refY, refZ);
	}

	@Override
	public void onDrawFrame(GL10 gl) {
		if (image != null)
		{
			NativePreRender();
	        renderBackground();
	        
	        if (shouldDrawScene)
	        {
	        	
	        	NativePreRenderScene();
	        	
	        	NativeRenderTriangle(trianglePoint1Tv.nativeObj, trianglePointRv.nativeObj);
	        	NativeRenderTriangle(trianglePoint2Tv.nativeObj, trianglePointRv.nativeObj);
	        	NativeRenderTriangle(trianglePoint3Tv.nativeObj, trianglePointRv.nativeObj);
	        	
	        	NativePostRenderScene();
	        }
	        NativePostRender();
		}
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		NativeRendererResize(width, height);
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
		NativeRendererSetUp();
	}
	
	public void renderBackground()
	{
		//NativeSetUp();
		camImageLock.lock();
		try
		{
			NativeRenderBackground(image.nativeObj);
		}
		finally
		{
			camImageLock.unlock();
		}
	}
	
	public void finalize()
	{
		NativeRelease();
	}
	
	//Setting up environment for rendering
	private native boolean NativeInit();
	private native boolean NativeRelease();
	private native boolean NativeRendererResize(int width, int height);
	private native boolean NativeRendererSetUp();
	private native boolean NativeRendererCleanUp();
	
	//Control functions
	private native boolean NativeUpdateReferencePoint(float x, float y, float z);
	private native boolean NativeUpdateCameraPosition(long addrMatRv, long addrMatTv);
	
	//Rendering codes
	private native boolean NativePreRender();
	private native boolean NativeRenderBackground(long addrBgMat);
	
	private native boolean NativePreRenderScene();
	private native boolean NativeRenderTriangle(long addrTv, long addrRv);
	private native boolean NativePostRenderScene();
	
	private native boolean NativePostRender();
	

}
